from django.contrib.auth import login
from django.shortcuts import render, redirect
from QQLoginTool.QQtool import OAuthQQ
from django.views import View
from django.conf import settings
from django import http
from . import models
from itsdangerous import TimedJSONWebSignatureSerializer
import re
from django_redis import get_redis_connection


def generate_openid_token(open_id):
    """
    加密openid
    :param open_id: 用户的openid
    :return: 加密后的open_id
    """
    serializer = TimedJSONWebSignatureSerializer(secret_key=settings.SECRET_KEY, expires_in=300)
    token = serializer.dumps({'openid': open_id})
    return token.decode()


def decode_open_id_token(data):
    """
    解密open_id
    :param data:获取页面提交过来的token进行解密
    :return:返回解密后的token
    """
    serializer = TimedJSONWebSignatureSerializer(secret_key=settings.SECRET_KEY, expires_in=300)
    try:
        data_dict = serializer.loads(data)
    except Exception as e:
        return None
    else:
        return data_dict.get('openid')


class QQAuthURLView(View):

    def get(self, request):
        """
        获取QQ登录url
        思路是点击QQ登录按钮获取settings文件配置信息获取QQ登录页面URL返回
        后端返回json数据，前端取出数据并跳转
        """
        state = request.GET.get('next', '/')
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI, state=state)
        login_url = oauth.get_qq_url()
        return http.JsonResponse({"login_url": login_url})


class QQAuthUserView(View):
    def get(self, request):
        """
        扫描登录成功回调地址，返回code,通过code获取access_token,最后获取open_id
        :param request:code,扫描成功qq服务器返回的code,state,登录之前的路径
        :return:如果已绑定用户直接修改登录状态，未绑定加密open_id返回绑定页面
        """
        code = request.GET.get('code', None)
        state = request.GET.get('state', "/")

        if code is None:
            return http.HttpResponseForbidden('缺少code')
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI)
        # 获取access_token
        access_token = oauth.get_access_token(code)
        # 获取open_id
        open_id = oauth.get_open_id(access_token)
        try:
            # 通过openid查找是否绑定美多用户。
            oauth_user = models.OAuthQQUser.objects.get(open_id=open_id)
        except models.OAuthQQUser.DoesNotExist:
            # 初次绑定
            token = generate_openid_token(open_id)
            return render(request, 'oauth_callback.html', context={'token': token})
        else:
            # 已绑定过qq，直接登录修改session和cookie状态
            qq_user = oauth_user.user
            login(request, qq_user)
            request.session.set_expiry(3600 * 24 * 2)

            response = redirect(state)
            response.set_cookie('username', qq_user.username, 3600 * 24 * 2)
            return response

    def post(self, request):

        """
        接收绑定用户页面post请求，如果输入的用户已存在直接绑定，不存在新建用户绑定
        :param request:
        :return:
        """
        sign_openid = request.POST.get('access_token')
        mobile = request.POST.get('mobile')
        pwd = request.POST.get('pwd')
        sms_code = request.POST.get('sms_code')

        if not all([sign_openid, mobile, pwd, sms_code]):
            return http.HttpResponseForbidden('参数不全')
        # 校验open_id
        open_id = decode_open_id_token(sign_openid)
        if not open_id:
            return http.HttpResponseForbidden('openid过期')
        # 校验手机号
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('手机号格式不对')
        # 校验密码
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseForbidden("密码格式不对，请输入8-20位")

        # 验证短信验证码是否正确
        redis_con = get_redis_connection('code')
        redis_sms_code = redis_con.get("sms_code_%s" % mobile)
        if redis_sms_code is None:
            return http.HttpResponseForbidden("短信验证码已过期，请重新获取")
        if sms_code != redis_sms_code.decode():
            return http.HttpResponseForbidden("短信验证码错误")
        # 判断用户是否注册，如果已注册查找数据验证密码并绑定open id，最后登录保持，
        # 如果未注册直接创建新用户，创建成功绑定openid，最后登录保持
        try:
            user = models.User.objects.get(phone=mobile)
        except models.User.DoesNotExist:
            user = models.User.objects.create_user(username=mobile, password=pwd, phone=mobile)
        else:
            if not user.check_password(pwd):
                return render(request, 'oauth_callback.html', {'qq_login_errmsg': '用户名或密码错误'})
        # 将用户绑定open id
        try:
            models.OAuthQQUser.objects.create(open_id=open_id, user=user)
        except Exception:
            return render(request, 'oauth_callback.html', {'qq_login_errmsg': 'QQ登录失败'})
        # 登录保持并返回之前页面
        login(request, user)
        request.session.set_expiry(3600 * 24 * 2)

        state = request.POST.get('state', '/')
        response = redirect(state)
        response.set_cookie('username', user.username, 3600 * 24 * 2)
        return response
